package com.company.zhishidian.thread.线程池;

import java.util.concurrent.*;

public class Threadpool {
    public static void main(String[] args) {
        // JDK自带的线程池
        // 创建
        // 缓存线程池，来个任务就建一个线程，优点：可被重复利用
        ExecutorService pool1 =  Executors.newCachedThreadPool();
        // 固定数量线程池，设置10个线程数 缺点：如果10个线程都在工作，此时进来一个任务，
        // 那么这个任务将被丢弃，第一个方法则不会
        ExecutorService pool2 =  Executors.newFixedThreadPool(10);
        // 单线程池 缺点：只有一个线程，其他任务进来，将会排队等待该线程执行结束
        ExecutorService pool3 =  Executors.newSingleThreadExecutor();
        // 未来执行的线程池  指代任务可以 延迟 到未来执行
        ExecutorService pool4 =  Executors.newScheduledThreadPool(5);

        // 阿里不建议用上述方式创建线程，建议以下方式创建

        // 阿里建议的手动创建方式
        ExecutorService pool5 = new ThreadPoolExecutor(
                5,// 核心线程数 默认情况下 即使为空闲 也不会被回收
                10,// 总线程数 核心线程数+非核心线程数  非核心线程一旦空闲就会被回收
                10,// 空闲线程存货时间
                TimeUnit.SECONDS,// 时间单位（秒）
                new LinkedBlockingDeque<>(),// 任务队列 用来排队 无界队列
                new ThreadFactory() {  // 创建线程工厂
                    @Override
                    public Thread newThread(Runnable r) {
                        return null;
                    }
                }
                // 拒绝策略 默认：丢弃新任务并抛弃异常  ；丢弃新任务不抛出异   ；用新任务替换旧任务
        );
        // 线程池满员执行顺序：此线程池中的核心线程任务满了，又进来了新的任务，将会先进入队列中等待，如果队列也满了，将会启用非核心线程
        // 之所以阿里不建议用定义好的 是因为定义好的中定义有 无界对列 那么当任务很多的时候 就会有爆炸的风险，造成 内存不足的现象

        // 线程任务
        Runnable r = new Runnable() {
            @Override
            public void run() {

            }
        };

        Callable c = new Callable() {
            @Override
            public Object call() throws Exception {
                return 100;
            }
        };
        // 两者区别：一个是原始的方式，一个是可以带返回值和抛出异常的

        // 传入线程任务，线程池 会 自动 管理 执行任务 （执行并不是指立即执行，任务也可能是在线程池中的队列中 ，也可能会被丢弃）
        pool5.execute(r);
        Future fu = pool5.submit(c);
        try {
            Integer in = (Integer)fu.get(); // 阻塞
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        // 线程池任务结束，一定要关掉
        pool5.shutdown();

        // 初始线程任务对比，如果啊换成 固定线程池 就会变慢很多因为每次只有5个
        pool1.execute(()->{
            for (int i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName()+"-"+i);
            }
        });
        pool1.shutdown();
    }
}
